﻿using System.Linq;
using System.Web;
using System.Xml;
using System.Xml.Linq;

using Com.FastSearch.SharePoint.Interfaces;
using Com.FastSearch.SharePoint.WebControls.ESPSearchWebParts.UI;
using Com.FastSearch.SharePoint.WebControls.ESPSearchWebParts.UI.Client;
using ESPWebPartsUnitTest.mock;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ESPWebPartsUnitTest
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class ESPSearchPagingTest
    {
        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        /// <summary>
        /// Test the paging with the following data:
        /// current page = 6 -> current offset = 50
        /// total results = 100
        /// Next Page available
        /// Prev Page available
        /// </summary>
        [TestMethod]
        public void BuildXmlPagingTest()
        {
            int totalResults = 200;
            int hitsPerPage = 10;
            int startOffset = 10;
            int expectedPages = 10; // Not including next and prev
            bool hasPrev = true;
            bool hasNext = true;
            bool hasFirst = false;
            int currentOffset = 50;

            XmlPagingTest(currentOffset, startOffset, totalResults, hitsPerPage, expectedPages, hasPrev, hasNext, hasFirst);
        }

        /// <summary>
        /// Test the paging with the following data:
        /// current page = 1 -> current offset = 0
        /// total results = 100
        /// Next Page available
        /// Prev Page NOT available
        /// </summary>
        [TestMethod]
        public void BuildXmlPagingTestNoPrev()
        {
            int totalResults = 100;
            int hitsPerPage = 10;
            int startOffset = 0;
            int expectedPages = 6; // Not including next and prev (1-6)
            bool hasPrev = false;
            bool hasNext = true;
            bool hasFirst = false;
            int currentOffset = 0;
            XmlPagingTest(currentOffset, startOffset, totalResults, hitsPerPage, expectedPages, hasPrev, hasNext, hasFirst);
        }

        /// <summary>
        /// Test the paging with the following data:
        /// current page = 11 -> current offset = 100
        /// total results = 100
        /// Next Page NOT available
        /// Prev Page available
        /// </summary>
        [TestMethod]
        public void BuildXmlPagingTestNoNext()
        {
            int totalResults = 100;
            int hitsPerPage = 10;
            int startOffset = 60;
            int expectedPages = 5; // Not including next and prev (7-11)
            bool hasPrev = true;
            bool hasNext = false;
            bool hasFirst = false;
            int currentOffset = 100;
            XmlPagingTest(currentOffset, startOffset, totalResults, hitsPerPage, expectedPages, hasPrev, hasNext, hasFirst);
        }


        [TestMethod]
        public void BuildXmlPagingTestLastPage()
        {
            int totalResults = 100;
            int hitsPerPage = 10;
            int startOffset = 50;
            int expectedPages = 5; // Not including next and prev (7-11)
            bool hasPrev = true;
            bool hasNext = false;
            bool hasFirst = false;
            int currentOffset = 90;
            XmlPagingTest(currentOffset, startOffset, totalResults, hitsPerPage, expectedPages, hasPrev, hasNext, hasFirst);
        }
        /// <summary>
        /// Test the paging with the following data:
        /// current page = 10 -> current offset = 90
        /// total results = 100
        /// Next Page available
        /// Prev Page available
        /// </summary>
        [TestMethod]
        public void BuildXmlPagingTestCloseToEnd()
        {
            int totalResults = 100;
            int hitsPerPage = 10;
            int startOffset = 40;
            int expectedPages = 6; // Not including next and prev (7-11)
            bool hasPrev = true;
            bool hasNext = true;
            bool hasFirst = true;
            int currentOffset = 80;
            XmlPagingTest(currentOffset, startOffset, totalResults, hitsPerPage, expectedPages, hasPrev, hasNext, hasFirst);
        }

        /// <summary>
        /// Test the paging with the following data:
        /// current page = 10 -> current offset = 90
        /// total results = 100
        /// Next Page available
        /// Prev Page available
        /// </summary>
        [TestMethod]
        public void BuildXmlPagingTestCloseToStart()
        {
            int totalResults = 100;
            int hitsPerPage = 10;
            int startOffset = 0;
            int expectedPages = 7; // Not including next and prev (7-11)
            bool hasPrev = true;
            bool hasNext = true;
            bool hasFirst = false;
            int currentOffset = 10;
            XmlPagingTest(currentOffset, startOffset, totalResults, hitsPerPage, expectedPages, hasPrev, hasNext, hasFirst);
        }


        /// <summary>
        /// Test the paging with the following data:
        /// current page = 10 -> current offset = 90
        /// total results = 100
        /// Next Page available
        /// Prev Page available
        /// </summary>
        [TestMethod]
        public void BuildXmlPagingTestCloseToStartWithGroup()
        {
            int totalResults = 100;
            int hitsPerPage = 10;
            int startOffset = 0;
            int expectedPages = 7; // Not including next and prev (7-11)
            bool hasPrev = true;
            bool hasNext = true;
            bool hasFirst = false;
            int currentOffset = 10;
            XmlPagingTest(currentOffset, startOffset, totalResults, hitsPerPage, expectedPages, hasPrev, hasNext, hasFirst, ESPSearchGroupEnum.Group1);
        }


        private void XmlPagingTest(int currentOffset, int startOffset, int totalResults, int hitsPerPage, int expectedPages, bool hasPrev, bool hasNext, bool hasFirst)
        {
            XmlPagingTest(currentOffset, startOffset, totalResults, hitsPerPage, expectedPages, hasPrev, hasNext, hasFirst, ESPSearchGroupEnum.Group0);
        }

        private void XmlPagingTest(int currentOffset, int startOffset, int totalResults, int hitsPerPage, int expectedPages, bool hasPrev, bool hasNext, bool hasFirst, ESPSearchGroupEnum searchGroup)
        {

            ESPSearchPaging paging = new ESPSearchPaging();

            paging.ESPSearchGroupID = searchGroup;

            HttpRequest request = new HttpRequest("test.aspx", "http://www.test.com/test.aspx", "k=test");
            XmlDocument xmldoc = paging.BuildXmlPaging(currentOffset, totalResults, hitsPerPage, request);
            XElement doc = XElement.Parse(xmldoc.InnerXml);
            AssertPagingXML(doc, hasPrev, hasNext, hasFirst, expectedPages, "/test.aspx?k=test&start1" +
                                                                  SearchRequest.GetPropertyPostfixForGroup(paging.ESPSearchGroupID) + "=__NUM__", currentOffset, startOffset, hitsPerPage);
        }

        private void AssertPagingXML(XElement doc, bool hasPrevNode, bool hasNextNode, bool hasFirstPageNode, int numPages, string urlTemplate,
                                     int currentOffset, int startOffset, int resultsPerPage)
        {
            if (hasPrevNode)
            {
                string url = urlTemplate.Replace("__NUM__", (currentOffset - resultsPerPage).ToString());
                AssertPrevNextPage(doc, "<Prev",url, "isPrevPage");
            }

            if (hasNextNode)
            {
                string url = urlTemplate.Replace("__NUM__", (currentOffset + resultsPerPage).ToString());
                AssertPrevNextPage(doc, "Next>", url, "isNextPage");
            }

            if (hasFirstPageNode)
            {
                string url = urlTemplate.Replace("__NUM__", "0");
                AssertPrevNextPage(doc, "<<First", url, "isFirstPage");
            }

            AssertPageNodes(doc, numPages, urlTemplate, currentOffset, startOffset, resultsPerPage);
        }

        private void AssertPageNodes(XElement doc, int numTotalPages, string urlTemplate, int currentOffset, int startOffset, int resultsPerPage)
        {
            var result = from page in doc.Descendants("Page")
            where (page.Attribute("isPrevPage").Value == "false" &&
                   page.Attribute("isNextPage").Value == "false" &&
                   page.Attribute("isFirstPage").Value == "false")
            select new
            {
                URL = page.Element("Url").Value,
                TEXT = page.Element("Text").Value,
                ISCURRRENT = page.Attribute("isCurrent").Value,
                ISNEXTPAGE = page.Attribute("isNextPage").Value,
                ISPREVPAGE = page.Attribute("isPrevPage").Value,
                ISFIRSTPAGE = page.Attribute("isFirstPage").Value
            };

            Assert.AreEqual<int>(numTotalPages, result.ToList().Count);

            int offset = startOffset;
            foreach(var page in result)
            {
                string text = ((offset / resultsPerPage) + 1).ToString();
                Assert.AreEqual<string>(text, page.TEXT);
                string url = urlTemplate.Replace("__NUM__", offset.ToString());
                Assert.AreEqual<string>(url, page.URL);
                Assert.AreEqual<string>("false", page.ISNEXTPAGE ,"Wrongly marked isNextPage!");
                Assert.AreEqual<string>("false", page.ISPREVPAGE, "Wrongly marked isPrevPage!");
                Assert.AreEqual<string>("false", page.ISFIRSTPAGE, "Wrongly marked isFirstPage!");

                if (offset == currentOffset)
                {
                    Assert.AreEqual<string>("true", page.ISCURRRENT, "Current page not marked!");
                } else
                {
                    Assert.AreEqual<string>("false", page.ISCURRRENT, "Wrong page marked as current!");
                }
                offset += resultsPerPage;
            }
        }



        private void AssertPrevNextPage(XElement doc, string text, string link, string attrName)
        {
            var result = from page in doc.Descendants("Page")
            where page.Attribute(attrName).Value == "true"
            select new
            {
                URL = page.Element("Url").Value,
                TEXT = page.Element("Text").Value
            };

            Assert.AreEqual<int>(1, result.ToList().Count, "Multiple or no Prev Pages!");
            foreach (var page in result)
            {
                Assert.AreEqual<string>(text, page.TEXT);
                Assert.AreEqual<string>(link, page.URL);
            }
        }

        private static IESPSearchResult GetDummyESPSearchResult()
        {

            ESPSearchResultMock testResu = new ESPSearchResultMock();
            testResu.DocCount = 1000;
            return testResu;
        }
    }
}